package net.main.dartcounter;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.*;

public class DartCounter extends JFrame implements ActionListener,WindowListener,FocusListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private final String dir = "stats";
	private GameHandler gh;
	
	// Create the menu
	private JMenuBar menubar;
	private JMenu menu;
	private JMenuItem mnuExit;
	private JMenuItem mnuRestart;
	
	public JLabel lblName1;
	public JLabel lblName2;
	public JLabel lblScore1;
	public JLabel lblScore2;
	public JTextField thrownScore;
	//public JTextField thrownScore2;
	
	private JComboBox<String> neededArrows;
	private JLabel lblTurn;
	
	private JButton apply;
	//private JButton apply2;
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void setupComponents(DartCounter MAIN_FRAME) {
		if(!new File(getDir()).exists()) {
			boolean success = (new File(getDir()).mkdir());
			if(success) {
				System.out.println("Succesfully created the directory: " + getDir());
				} else {
				System.out.println("Could not create the following directory:\n" +
						"- " + getDir() + 
						"\nThis might be because " + getName() + " does not have the right permissions.");
			}
		}
		
		addWindowListener(this);
		
		menubar = new JMenuBar();
		menu = new JMenu("File");
		menu.setMnemonic(KeyEvent.VK_F);
		
		mnuExit = new JMenuItem("Exit");
		mnuExit.addActionListener(this);
		mnuExit.setMnemonic(KeyEvent.VK_X);
		mnuExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK));
		
		mnuRestart = new JMenuItem("Restart");
		mnuRestart.addActionListener(this);
		mnuRestart.setMnemonic(KeyEvent.VK_R);
		mnuRestart.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK));
		
		menu.add(mnuRestart);
		menu.add(mnuExit);
		
		menubar.add(menu);
		MAIN_FRAME.setJMenuBar(menubar);
		
		JPanel MAIN_PANEL = new JPanel();
		MAIN_PANEL.setLayout(new GridLayout(4, 2, 10, 10));
		MAIN_FRAME.add(MAIN_PANEL);
		
		lblName1 = new JLabel();
		lblName1.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 40));
		lblName1.setForeground(Color.RED);
		lblName2 = new JLabel();
		lblName2.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 40));
		lblName2.setForeground(Color.RED);
		
		lblScore1 = new JLabel();
		lblScore2 = new JLabel();
		
		thrownScore = new JTextField("");
		thrownScore.addFocusListener(this);
		thrownScore.setForeground(Color.RED);
		/*thrownScore2 = new JTextField("");
		thrownScore2.addFocusListener(this);
		thrownScore2.setForeground(Color.RED);*/
		
		String[] nrArrows = {"1", "2", "3"};
		neededArrows = new JComboBox(nrArrows);
		neededArrows.setSelectedIndex(2);
		neededArrows.addActionListener(this);
		
		lblTurn = new JLabel();
		
		apply = new JButton("OK");
		//apply2 = new JButton("OK");
		
		apply.addActionListener(this);
		//apply2.addActionListener(this);
		
		MAIN_PANEL.add(lblName1);
		MAIN_PANEL.add(lblName2);
		
		MAIN_PANEL.add(lblScore1);
		MAIN_PANEL.add(lblScore2);
		
		MAIN_PANEL.add(thrownScore);
		MAIN_PANEL.add(neededArrows);
		
		MAIN_PANEL.add(lblTurn);
		MAIN_PANEL.add(apply);
		//MAIN_PANEL.add(apply2);
		
		MAIN_FRAME.setVisible(true);
		
		updateUI();
	}
	
	public DartCounter(String title) {
		super(title);
		gh = new GameHandler(this);
		setupComponents(this);
	}
	
	public static void main(String[] args) {
		DartCounter MAIN_FRAME = new DartCounter("Dart Counter");
		MAIN_FRAME.setSize(600, 400);
		MAIN_FRAME.setResizable(false);
		MAIN_FRAME.setLocation(new Point(150, 150));
		MAIN_FRAME.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource().equals(apply)/* || e.getSource().equals(apply2)*/) {
			int thrown = 0;
			int arrows = 0;
			int result_Singles = 0;
			int result_Doubles = 0;
			int result_Triples = 0;
			int result_Total = 0;
			
			String str_Thrown = thrownScore.getText();
			
			if(str_Thrown.equals("")) {
				JOptionPane.showMessageDialog(this, "Enter what you have thrown!");
				return;
			} else if(str_Thrown.equals("0")) {
				arrows = ask_Arrows();
			} else {
				String result;
				
				Pattern patternDoubles = Pattern.compile("(d|D){1}\\d{1,2}");
				Matcher matcher = patternDoubles.matcher(str_Thrown);
				while(matcher.find()) {
					if(arrows < 3) {
						arrows++;
						result = matcher.group().replace("d", "");
						result = result.replace("D", "");
						
						if(Integer.parseInt(result) < 21 || Integer.parseInt(result) == 25) {
							result_Doubles = result_Doubles + Integer.parseInt(result) * 2;
						}
						str_Thrown = str_Thrown.replace(matcher.group(), "");
					}
				}
				
				Pattern patternTriples = Pattern.compile("(t|T){1}\\d{1,2}", Pattern.CASE_INSENSITIVE);
				matcher = patternTriples.matcher(str_Thrown);
				while(matcher.find()) {
					if(arrows < 3) {
						arrows++;
						result = matcher.group().replace("t", "T");
						result = result.replace("T", "");
						
						if(Integer.parseInt(result) < 21) {
							result_Triples = result_Triples + Integer.parseInt(result) * 3;
						}
						str_Thrown = str_Thrown.replace(matcher.group(), "");
					}
				}
				
				Pattern patternSingles = Pattern.compile("(s|S){0,1}\\d{1,2}");
				matcher = patternSingles.matcher(str_Thrown);
				while(matcher.find()) {
					if(arrows < 3) {
						arrows++;
						result = matcher.group().replace("s", "S");
						result = result.replace("S", "");
						
						if(Integer.parseInt(result) < 21 || Integer.parseInt(result) == 25) {
							result_Singles = result_Singles + Integer.parseInt(result);
						}
						str_Thrown = str_Thrown.replace(matcher.group(), "");
					}
				}
				result_Total = result_Singles + result_Doubles + result_Triples;
				thrown = result_Total;
				
				/*JOptionPane.showMessageDialog(this, "You threw: " + thrown +
						"\nwith " + arrows + " arrows." +
						"\nS: " + result_Singles +
						"\nD: " + result_Doubles +
						"\nT: " + result_Triples);*/
			}
			
			int turn = gh.getTurn();
			int newScore = gh.getScore(turn) - thrown;
			
			if(newScore == 0) {
				gh.setScore(0,turn);
				JOptionPane.showMessageDialog(this, convert_Label("<red>" + gh.getName(turn) + "<black> wins the game!"));
				gh.addThrownArrows(arrows, turn);
				
				updateScores();
				askRestart();
			} else if(newScore < 0 || newScore == 1) {
				arrows = ask_Arrows();
				gh.addThrownArrows(arrows, turn);
			} else {
				gh.addThrownArrows(3, turn);
				gh.setScore(newScore, turn);
			}
			
			gh.nextTurn();
			updateScores();
		} else if(e.getSource().equals(mnuRestart)) {
			askRestart();
		} else if(e.getSource().equals(mnuExit)) {
			exitProgram(false);
		}
	}
	
	public int getThrown(int player) {
		String thrown = null;
		int intThrown = -1;
		
		thrown = thrownScore.getText();
		
		if(is_Numeric(thrown)) {
			intThrown = Integer.parseInt(thrown);
		} else {
			JOptionPane.showMessageDialog(this, "Please fill in a number!");
			return -1;
		}
		
		return intThrown;
	}
	
	public int ask_Arrows() {
		int arrows = 0;
		for(;;) {
			String strArrows = JOptionPane.showInputDialog("How many arrows did you throw?");
			if(strArrows.matches("[0-3]{1}")) {
				arrows = Integer.parseInt(strArrows);
				break;
			}
		}
		return arrows;
	}
	
	public void updateScores() {
		lblScore1.setText(convert_Label("Score: <red>" + gh.getScore(1) + 
				"<black>\nThrown arrows: <red>" + gh.getThrownArrows(1) + 
				"<black>\nAvg per Arrow: <red>" + gh.getAveragePerArrow(1) + ""));
		lblScore2.setText(convert_Label("Score: <red>" + gh.getScore(2) + 
				"<black>\nThrown arrows: <red>" + gh.getThrownArrows(2) + 
				"<black>\nAvg per Arrow: <red>" + gh.getAveragePerArrow(2) + ""));
		thrownScore.setText("");
		lblTurn.setText(convert_Label("<red>" + gh.getName(gh.getTurn()) + "\'s</red> turn."));
	}
	
	public void updateUI() {
		lblName1.setText(gh.getName(1));
		lblName2.setText(gh.getName(2));
		
		updateScores();
	}
	
	public boolean is_Numeric(Object obj) {
		try {
			return true;
		} catch(Exception ex) {
			return false;
		}
	}
	
	public int convert_to_Numeric(String nr) {
		try {
			return Integer.parseInt(nr);
		} catch(Exception ex) {
			return -1;
		}
	}
	
	public String convert_Label(String msg) {
		msg = msg.replaceAll("<red>", "<font color='red'>");
		msg = msg.replaceAll("<black>", "<font color='black'>");
		return "<html>" + msg.replaceAll("\n", "<br />");
	}
	
	public void exitProgram(boolean force) {
		int close = -1;
		if(force == false) {
			close = JOptionPane.showConfirmDialog(this, "Are you sure you want to exit?", "Exit Dart Counter?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
		}
		
		if(force == true || close == 0 & force == false) {
			dispose();
			System.exit(0);
		}
	}
	
	public void askRestart() {
		int restart = JOptionPane.showConfirmDialog(this, "Do you want to restart?", "Restart Dart Counter", JOptionPane.YES_NO_OPTION);
		
		if(restart == 0) {
			gh.restartGame();
		} else if(restart == 1) {
			exitProgram(true);
		}
	}
	
	@Override
	public void windowActivated(WindowEvent e) {
	}
	@Override
	public void windowClosed(WindowEvent e) {
	}
	@Override
	public void windowClosing(WindowEvent e) {
		exitProgram(false);
	}

	@Override
	public void windowDeactivated(WindowEvent e) {
		
	}

	@Override
	public void windowDeiconified(WindowEvent e) {
	}

	@Override
	public void windowIconified(WindowEvent e) {
	}

	@Override
	public void windowOpened(WindowEvent e) {
	}

	@Override
	public void focusGained(FocusEvent e) {
		if(e.getSource().equals(thrownScore)) {
			thrownScore.setText("");
		}/* else if(e.getSource().equals(thrownScore2)) {
			thrownScore2.setText("");
		}*/
	}

	@Override
	public void focusLost(FocusEvent e) {
	}

	/**
	 * @return the dir
	 */
	public String getDir() {
		return dir;
	}
}
